package com.star.spring.redis.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类，提供各种Redis操作
 */
@Slf4j
@Component
public class RedisUtil {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // ============================== 通用操作方法 ==============================

    /**
     * 设置过期时间
     *
     * @param key      键
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            log.error("Set expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 获取过期时间
     *
     * @param key 键
     * @return 时间(秒) 返回0代表永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            log.error("Has key error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个或多个值
     */
    public void delete(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(Arrays.asList(key));
            }
        }
    }

    // ============================== String类型操作 ==============================

    /**
     * 获取缓存
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 设置缓存
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("Set error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 设置缓存并设置过期时间
     *
     * @param key      键
     * @param value    值
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error("Set with expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 递增因子
     * @return 递增后的值
     */
    public long increment(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 递减因子
     * @return 递减后的值
     */
    public long decrement(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().decrement(key, delta);
    }

    // ============================== Hash类型操作 ==============================

    /**
     * 获取Hash中的数据
     *
     * @param key     键
     * @param hashKey Hash键
     * @return Hash值
     */
    public Object hashGet(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 获取Hash中的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hashEntries(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 设置Hash数据
     *
     * @param key     键
     * @param hashKey Hash键
     * @param value   值
     * @return true成功 false失败
     */
    public boolean hashSet(String key, String hashKey, Object value) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
            return true;
        } catch (Exception e) {
            log.error("Hash set error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 设置Hash数据并设置过期时间
     *
     * @param key      键
     * @param hashKey  Hash键
     * @param value    值
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean hashSet(String key, String hashKey, Object value, long time, TimeUnit timeUnit) {
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            log.error("Hash set with expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 设置多个Hash数据
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true成功 false失败
     */
    public boolean hashSetAll(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            log.error("Hash set all error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 设置多个Hash数据并设置过期时间
     *
     * @param key      键
     * @param map      对应多个键值
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean hashSetAll(String key, Map<String, Object> map, long time, TimeUnit timeUnit) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            log.error("Hash set all with expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 删除Hash表中的值
     *
     * @param key      键
     * @param hashKeys Hash键，可以是多个
     */
    public void hashDelete(String key, Object... hashKeys) {
        redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 判断Hash表中是否有该项的值
     *
     * @param key     键
     * @param hashKey Hash键
     * @return true存在 false不存在
     */
    public boolean hashHasKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * Hash递增
     *
     * @param key     键
     * @param hashKey Hash键
     * @param delta   递增因子
     * @return 递增后的值
     */
    public double hashIncrement(String key, String hashKey, double delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * Hash递减
     *
     * @param key     键
     * @param hashKey Hash键
     * @param delta   递减因子
     * @return 递减后的值
     */
    public double hashDecrement(String key, String hashKey, double delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    // ============================== List类型操作 ==============================

    /**
     * 获取List缓存的内容
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置，-1代表所有值
     * @return List
     */
    public List<Object> listRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            log.error("List range error: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取List缓存的长度
     *
     * @param key 键
     * @return List大小
     */
    public long listSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            log.error("List size error: {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 通过索引获取List中的值
     *
     * @param key   键
     * @param index 索引 index>=0时，0表头，1第二个元素，依次类推；index<0时，-1表尾，-2倒数第二个元素，依次类推
     * @return 值
     */
    public Object listIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            log.error("List index error: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 将值放入List缓存
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean listRightPush(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            log.error("List right push error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将值放入List缓存并设置过期时间
     *
     * @param key      键
     * @param value    值
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean listRightPush(String key, Object value, long time, TimeUnit timeUnit) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            log.error("List right push with expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将多个值放入List缓存
     *
     * @param key    键
     * @param values 值
     * @return true成功 false失败
     */
    public boolean listRightPushAll(String key, List<Object> values) {
        try {
            redisTemplate.opsForList().rightPushAll(key, values);
            return true;
        } catch (Exception e) {
            log.error("List right push all error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将多个值放入List缓存并设置过期时间
     *
     * @param key      键
     * @param values   值
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean listRightPushAll(String key, List<Object> values, long time, TimeUnit timeUnit) {
        try {
            redisTemplate.opsForList().rightPushAll(key, values);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            log.error("List right push all with expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 根据索引修改List中的值
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return true成功 false失败
     */
    public boolean listSet(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            log.error("List set error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 移除List中的值
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long listRemove(String key, long count, Object value) {
        try {
            return redisTemplate.opsForList().remove(key, count, value);
        } catch (Exception e) {
            log.error("List remove error: {}", e.getMessage(), e);
            return 0;
        }
    }

    // ============================== Set类型操作 ==============================

    /**
     * 获取Set中的所有值
     *
     * @param key 键
     * @return Set
     */
    public Set<Object> setMembers(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            log.error("Set members error: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 判断Set是否包含value
     *
     * @param key   键
     * @param value 值
     * @return true存在 false不存在
     */
    public boolean setIsMember(String key, Object value) {
        try {
            return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value));
        } catch (Exception e) {
            log.error("Set is member error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将数据放入Set缓存
     *
     * @param key    键
     * @param values 值，可以是多个
     * @return 成功个数
     */
    public long setAdd(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            log.error("Set add error: {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 将数据放入Set缓存并设置过期时间
     *
     * @param key      键
     * @param time     时间
     * @param timeUnit 时间单位
     * @param values   值，可以是多个
     * @return 成功个数
     */
    public long setAdd(String key, long time, TimeUnit timeUnit, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return count;
        } catch (Exception e) {
            log.error("Set add with expire error: {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 获取Set缓存的长度
     *
     * @param key 键
     * @return 长度
     */
    public long setSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            log.error("Set size error: {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 移除Set中的值
     *
     * @param key    键
     * @param values 值，可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
            log.error("Set remove error: {}", e.getMessage(), e);
            return 0;
        }
    }

    // ============================== ZSet类型操作 ==============================

    /**
     * 添加ZSet元素
     *
     * @param key   键
     * @param value 值
     * @param score 分数
     * @return true成功 false失败
     */
    public boolean zSetAdd(String key, Object value, double score) {
        try {
            return Boolean.TRUE.equals(redisTemplate.opsForZSet().add(key, value, score));
        } catch (Exception e) {
            log.error("ZSet add error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 添加ZSet元素并设置过期时间
     *
     * @param key      键
     * @param value    值
     * @param score    分数
     * @param time     时间
     * @param timeUnit 时间单位
     * @return true成功 false失败
     */
    public boolean zSetAdd(String key, Object value, double score, long time, TimeUnit timeUnit) {
        try {
            boolean result = Boolean.TRUE.equals(redisTemplate.opsForZSet().add(key, value, score));
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return result;
        } catch (Exception e) {
            log.error("ZSet add with expire error: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 获取ZSet指定范围的元素
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置，-1代表所有值
     * @return Set
     */
    public Set<Object> zSetRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().range(key, start, end);
        } catch (Exception e) {
            log.error("ZSet range error: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取ZSet中指定分数范围的元素
     *
     * @param key 键
     * @param min 最小分数
     * @param max 最大分数
     * @return Set
     */
    public Set<Object> zSetRangeByScore(String key, double min, double max) {
        try {
            return redisTemplate.opsForZSet().rangeByScore(key, min, max);
        } catch (Exception e) {
            log.error("ZSet range by score error: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取ZSet中元素的分数
     *
     * @param key   键
     * @param value 值
     * @return 分数
     */
    public Double zSetScore(String key, Object value) {
        try {
            return redisTemplate.opsForZSet().score(key, value);
        } catch (Exception e) {
            log.error("ZSet score error: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 移除ZSet中的元素
     *
     * @param key    键
     * @param values 值，可以是多个
     * @return 移除的个数
     */
    public long zSetRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForZSet().remove(key, values);
        } catch (Exception e) {
            log.error("ZSet remove error: {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 获取ZSet缓存的长度
     *
     * @param key 键
     * @return 长度
     */
    public long zSetSize(String key) {
        try {
            return redisTemplate.opsForZSet().size(key);
        } catch (Exception e) {
            log.error("ZSet size error: {}", e.getMessage(), e);
            return 0;
        }
    }
}
